#include "ubvm_cylinder.h"
#include "DIVA_Manager.h"
#include <sstream>
#include "xParameterPack.h"
#include "vmLibrary.h"
#include "EntityMaterialInstance.h"
// 
//
//
const int NSIDES = 30 ;
const int NRINGS = 60 ;
void create_cylinder(float r, float h, int nsides,Ogre::ManualObject* manual);
int ubvm_cylinder::_UNIQUE_INT = 0 ;
ubvm_cylinder::ubvm_cylinder(xParameterPack xpp):DIVA_VM(xpp){

	int radius_port = vmLibrary::instance().get_vm_default_input_parameters().size();
	_vm_radius = xpp.paras[radius_port].val_int_ptr ; // set up the private attributes
	_vm_height = xpp.paras[radius_port+1].val_int_ptr ;

	init_default_parameters();
}
/// destructor
ubvm_cylinder::~ubvm_cylinder(){
}

void ubvm_cylinder::load_3Dresources() {

	const int COLOR_MODULATE_PARAM_INDEX = 1 ;
	_mgr = DIVA_Manager::getInstance()->getSceneManager();
	
	_manual_name = "cylinder" + Ogre::StringConverter::toString(_UNIQUE_INT) ;
	_manual = _mgr->createManualObject(_manual_name);
	
	create_cylinder((*_vm_radius),(*_vm_height), NSIDES, _manual); // 4 sides and  8 rings
  

	// convert it to mesh, because we want to change the color 
	_meshptr = _manual->convertToMesh("cylindershape"+_UNIQUE_INT);
	_mesh_name = "cylindershape"+_UNIQUE_INT ;
	_UNIQUE_INT++ ;
	
	_ent = _mgr->createEntity(getNewUniqueName(), _meshptr->getName());
	_SceneNode->attachObject(_ent);
}
void ubvm_cylinder::set_default_values() {

	_vm_rx_val = 0 ;
	_vm_ry_val = 0 ;
	_vm_rz_val = 0 ;

	Ogre::Vector3 sz = _ent->getBoundingBox().getSize();
	_vm_init_sizex = sz.x ;
	_vm_init_sizey = sz.y ;
	_vm_init_sizez = sz.z ;

	_vm_sizex_val = sz.x ;
	_vm_sizey_val = sz.y ;
	_vm_sizez_val = sz.z ;

	_vm_sizexscale_val = 1.0 ;
	_vm_sizeyscale_val = 1.0 ;
	_vm_sizezscale_val = 1.0 ;

	_vm_r_val = 0.2;
	_vm_g_val = 0.2;
	_vm_b_val = 0.2;
	_vm_transparency_val = 1.0 ;

	_vm_yaw_val = 0 ;
	_vm_pitch_val = 0 ;
	_vm_roll_val = 0 ;

}
void ubvm_cylinder::reg_event_entity() {
	
	// register the relation of the entity and vm in diva manager
	// When this entity is clicked, mouse/keyboard VM will be passed to this VM
	// By default it can be only one entity representing this VM
	VL_regBoundingBox(_ent);

}
void ubvm_cylinder::init_private_attrs_started() {
	
}
void ubvm_cylinder::init_private_attrs_ended() {}

void ubvm_cylinder::VMValueUpdated() {

	int radius_port = vmLibrary::instance().get_vm_default_input_parameters().size();
	if (_para_onoff[radius_port] || _para_onoff[radius_port+1] ) {

		DIVA_Manager::getInstance()->dereg_MovableObj_VM_relation(_ent,this); 
		// first, we should free the previous created resources
		_SceneNode->detachObject(_ent->getName());  // deattach 
		_mgr->destroyManualObject(_manual);
		_mgr->destroyEntity(_ent); 
		Ogre::MeshManager::getSingleton().remove(_mesh_name);

		// now, we create another new donut according to the updated values
		_manual = _mgr->createManualObject("cynlinder"+_UNIQUE_INT);
		_manual_name = "cynlinder"+_UNIQUE_INT ;
	
		create_cylinder((*_vm_radius),(*_vm_height), NSIDES, _manual); // 4 sides and  8 rings
		// convert it to mesh, because we want to change the color 
		_meshptr = _manual->convertToMesh("cynlindershape"+_UNIQUE_INT);
		_mesh_name = "cynlindershape"+_UNIQUE_INT ;
		_UNIQUE_INT++ ;
		_ent = _mgr->createEntity(getNewUniqueName(), _meshptr->getName());
		_SceneNode->attachObject(_ent);
		DIVA_Manager::getInstance()->reg_MovableObj_VM_relation(_ent,this); // register the new entity and vm relation
		                                                                    // if this step is not done, the dragging will
																			// not working
	}
	DIVA_VM::VMValueUpdated();
}

void ubvm_cylinder::setBodyScale(Ogre::Vector3 scale) {
	_SceneNode ->setScale(scale);
}
bool ubvm_cylinder::isBodyScaleWrtSceneNode() { return true ; }

Ogre::Vector3 ubvm_cylinder::getOriginalBodySize() {
	Ogre::AxisAlignedBox temp = _ent ->getBoundingBox();	
	Ogre::Vector3 size = temp.getSize(); 
	return size ;
}

Ogre::Vector3 ubvm_cylinder::getActualSize() {
	return getOriginalBodySize() * _SceneNode->getScale();
}
Ogre::Vector3 ubvm_cylinder::getBodyScale() {
	return _SceneNode->getScale();
}

void create_cylinder(float radius, float height, int nsides, Ogre::ManualObject *manual)
{
  /*
  int i, j;
  float theta, phi, theta1, phi1;
  float p0[03], p1[3], p2[3], p3[3];
  float n0[3], n1[3], n2[3], n3[3];
  int index ;
  */
	float theta ;
	manual->begin("TextureModColor", Ogre::RenderOperation::OT_TRIANGLE_LIST);

    //manual->begin("BaseWhiteNoLighting", RenderOperation::OT_LINE_STRIP);
    
    unsigned point_index = 0;
    for(theta = 0; theta <= 2 * Ogre::Math::PI; theta += Ogre::Math::PI / nsides) {
		float theta1 = theta + Ogre::Math::PI / nsides ;

		// draw the first triangle to form a rectangle
        manual->position(radius * cos(theta), -height/2, radius * sin(theta));
		manual->index(point_index++);
		manual->position(radius * cos(theta), height/2, radius * sin(theta));
		manual->index(point_index++);
		manual->position(radius * cos(theta1), height/2 , radius * sin(theta1));
		manual->index(point_index++);
	
		// draw the second triangle 
		manual->position(radius * cos(theta1), height/2 , radius * sin(theta1));
		manual->index(point_index++);
		manual->position(radius * cos(theta1), -height/2 , radius * sin(theta1));
		manual->index(point_index++);
		manual->position(radius * cos(theta), -height/2, radius * sin(theta));
		manual->index(point_index++);

		// draw the triangle to the center of the bottom circle, the order need to be reverse
		// to make the norm vector face downward 
		manual->position(radius * cos(theta), -height/2, radius * sin(theta));
		manual->index(point_index++);
		manual->position(radius * cos(theta1),-height/2, radius * sin(theta1));
		manual->index(point_index++);
		manual->position(0,-height/2,0);
        manual->index(point_index++);

		// draw the triangle to the center of the manual, the order need to be reverse
		// to make the norm vector face downward 
		manual->position(radius * cos(theta), height/2, radius * sin(theta));
		manual->index(point_index++);
		manual->position(0,height/2,0);
        manual->index(point_index++);
		manual->position(radius * cos(theta1),height/2, radius * sin(theta1));
		manual->index(point_index++);
		
    }
	manual->end();
}